﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;

namespace ESpace
{
    public class EStream
    {
        String FName;
        FileStream Sv;
        BinaryWriter w = null;
        BinaryReader r = null;

        //конструктор
        public EStream(String FN)
        {
            FName = FN;    
        }
        //---------------------------------------------------------------------------
        #region OpenClose

        public void OpenLoad()
        {
            Sv = new FileStream(FName, FileMode.Open, FileAccess.Read);
            r = new BinaryReader(Sv);
        }
        public void OpenSave()
        {
            Sv = new FileStream(FName, FileMode.Create);
            w = new BinaryWriter(Sv);
        }

        public void Close()
        {
            if (r != null) r.Close();
            else w.Close();
            Sv.Close();
        }
       
        #endregion OpenClose
        //---------------------------------------------------------------------------
        public String LoadStr()
        {
            String str = "";
            try
            {
                int sz = r.ReadInt32();
                for (int i = 0; i < sz; i++)
                    str += r.ReadChar();
            }
            catch { };
            return str;
        }
        public void SaveStr(String s)
        {
            int sz = 0;
            if(s!=null) sz = s.Length;
            w.Write(sz);
            for (int i = 0; i < sz; i++)
            {
                w.Write((char)s[i]);
            }
        }
        //---------------------------------------------------------------------------
        public byte[] LoadBuf()
        {
            int sz = LoadInt();
            return r.ReadBytes(sz);
        }
        public void SaveBuf(byte[] buf)
        {
            SaveInt(buf.Length);
            w.Write(buf);
        }
        //---------------------------------------------------------------------------
        public Bitmap LoadBmp()
        {
            int w = LoadInt();
            int h = LoadInt();
            System.Drawing.Imaging.PixelFormat pf = (System.Drawing.Imaging.PixelFormat)LoadInt();
            byte[] buf = LoadBuf();

            Bitmap bmp = new Bitmap(w, h);
            
            // блокируем bmp
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            System.Drawing.Imaging.BitmapData bmpData =
                bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, pf);

            // находим адрес на первую линию bmp
            IntPtr ptr = bmpData.Scan0;

            // копируем массив в bmp
            System.Runtime.InteropServices.Marshal.Copy(buf, 0, ptr, bmpData.Stride * bmp.Height);

            // разблокируем bmp.
            bmp.UnlockBits(bmpData);       
            
            return bmp;
        }
        public void SaveBmp(Bitmap bmp)
        {
            // сохраняем размеры bmp
            SaveInt(bmp.Width);
            SaveInt(bmp.Height);
            SaveInt((int)bmp.PixelFormat);

            // блокируем bmp
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            System.Drawing.Imaging.BitmapData bmpData =
                bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);

            // находим адрес на первую линию bmp
            IntPtr ptr = bmpData.Scan0;

            // создаем массив байт
            int sz = bmpData.Stride * bmp.Height;
            byte[] rgbValues = new byte[sz];

            // копируем значения RGB в массив
            System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, sz);

            // сохраняем массив
            SaveBuf(rgbValues);

            // разблокируем bmp.
            bmp.UnlockBits(bmpData);   
        }
        //---------------------------------------------------------------------------
        public DateTime LoadDate()
        {
            return new DateTime(r.ReadInt64());
        }
        public void SaveDate(DateTime dt)
        {
            w.Write(dt.Ticks);
        }
        //---------------------------------------------------------------------------
        public int LoadInt()
        {
            return r.ReadInt32();
        }
        public void SaveInt(int i)
        {
            w.Write(i);
        }
        //---------------------------------------------------------------------------
        public double LoadDouble()
        {
            return r.ReadDouble();
        }
        public void SaveDouble(double d)
        {
            w.Write(d);
        }
        //---------------------------------------------------------------------------
        public byte LoadByte()
        {
            return r.ReadByte();
        }
        public void SaveByte(byte b)
        {
            w.Write(b);
        }
        //---------------------------------------------------------------------------
        public bool LoadBool()
        {
            return r.ReadBoolean();
        }
        public void SaveBool(bool b)
        {
            w.Write(b);
        }
        //---------------------------------------------------------------------------
        public long LoadLong()
        {
            return r.ReadInt64();
        }
        public void SaveLong(long b)
        {
            w.Write(b);
        }
        //---------------------------------------------------------------------------

        #region *** Сохранение по версиям ************************************************

        /// <summary>
        /// Сохраняет объект в необходимой версии
        /// </summary>
        /// <param name="fPath">путь к файлу</param>
        /// <param name="ActVer">версия</param>
        /// <param name="funcList">список функций сохранения для каждой версии</param>
        public static void SaveObject(String fPath, int ActVer, List<SLObjectFunc> funcList)
        {
            // ищем функцию для необходимой версии
            int ind = -1;
            for (int i = 0; i < funcList.Count; i++)
                if (funcList[i].ver == ActVer)
                {
                    ind = i;
                    break;
                }
            // если фия не найдена, генерируем исключение
            if (ind == -1)
                throw new Exception("Не найдена функция для сохранения в версии " + ActVer.ToString());
            
            // сохраняем
            EStream st = new EStream(fPath);
            st.OpenSave();
            st.SaveInt(ActVer);
            funcList[ind].func(st);
            st.Close();
        }

        public static int LoadObject(String fPath, List<SLObjectFunc> funcList)
        {
            EStream st = new EStream(fPath);
            st.OpenLoad();
            int ver = st.LoadInt();
            int ind = -1;
            for (int i = 0; i < funcList.Count; i++)
                if (funcList[i].ver == ver)
                {
                    ind = i;
                    break;
                }
            if (ind == -1)
                throw new Exception("Не найдена функция для загрузки в версии " + ver.ToString());

            funcList[ind].func(st);
            st.Close();
            return ver;
        }

        #endregion *** Сохранение по версиям ************************************************

    }

    #region *** Классы для Сохранения по версиямn ************************************************

    public delegate void SLObjectDelegate(EStream st);

    public class SLObjectFunc
     {
         public SLObjectDelegate func;
         public int ver;
         public SLObjectFunc(SLObjectDelegate Func, int Ver)
         {
             func = Func;
             ver = Ver;
         }
     }

    /*
        void Save(String fPath)
        {
            List<SLObjectFunc> funcL = new List<SLObjectFunc>();
            funcL.Add(new SLObjectFunc(new SLObjectDelegate(Save0), 0));
            funcL.Add(new SLObjectFunc(new SLObjectDelegate(Save1), 1));
            EStream.SaveObject(fPath, ActVer, funcL);
        }

        void Load(String fPath)
        {
            List<SLObjectFunc> funcL = new List<SLObjectFunc>();
            funcL.Add(new SLObjectFunc(new SLObjectDelegate(Load0), 0));
            funcL.Add(new SLObjectFunc(new SLObjectDelegate(Load1), 1));
            EStream.LoadObject(fPath, funcL);
        }

        void Save0(EStream st)
        { 
        
        }
      
        void Save1(EStream st)
        { 
        
        }

        void Load0(EStream st)
        {

        }
       
        void Load1(EStream st)
        {

        }
 
 */

    #endregion *** Классы для Сохранения по версиям ************************************************

    /// <summary> тип с разбивкой пути файла на папку, имя, расширение</summary>
    public struct EFile
    {
        public string Name;
        public string Ext;
        public string dPath;

        public string NameExt
        {
            get
            {
                return Name + "." + Ext;
            }
        }

        public string fPath
        {
            get
            {
                return dPath + "\\" + Name + "." + Ext;
            }
        }

        public EFile(String fPath)
        {
            Name = "";
            Ext = "";
            dPath = "";
            for (int i = (fPath.Length - 1); i >= 0; i--)
            {
                if (Ext == "")
                {
                    if (fPath[i] == '.') Ext = fPath.Substring(i + 1);
                }
                else if (fPath[i] == '\\')
                {
                    Name = fPath.Substring(i + 1, fPath.Length - (i + 2) - Ext.Length);
                    dPath = fPath.Substring(0, i);
                    break;
                }
            }
        }

        /// <summary>Получить имя файла, пригодное для сохранения (все спец-символы удаляются из строки)</summary>
        public static String GetValidFileName(String text)
        {
            return text.Replace("\\", "").Replace("/", "").Replace(":", "").Replace("?", "").Replace("\"", "").Replace("<", "").Replace(">", "").Replace("|", "").Trim();
        }

    }

}



